package com.lfz.demo.controller;

import com.lfz.demo.common.enums.LogType;
import com.lfz.demo.common.enums.MenuType;
import com.lfz.demo.common.target.HoneyLogs;
import com.lfz.demo.entity.User;
import com.lfz.demo.service.UserService;
import com.lfz.demo.utils.RedisUtil;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author lfz
 * @date 2025/3/31 17:40
 */
@RestController
@RequestMapping("/file")
public class UploadController {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    // 缓存时间常量（单位：分钟）
    private static final String CACHE_PREFIX = "userMenu:"; //缓存键前缀，避免键冲突。

    @Autowired
    private UserService userService;
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 获取文件的扩展名
     * @param originalFilename 原始文件名
     * @return 文件的扩展名，如果没有则返回空字符串
     */
    public static String getFileExtension(String originalFilename) {
        // 查找文件名中最后一个点号的索引位置
        int lastDotIndex = originalFilename.lastIndexOf(".");
        // 检查是否存在点号，并且点号不是文件名的最后一个字符
        if (lastDotIndex != -1 && lastDotIndex < originalFilename.length() - 1) {
            // 如果满足条件，截取从最后一个点号开始到字符串末尾的部分作为扩展名
            return originalFilename.substring(lastDotIndex);
        }
        // 如果不满足条件，说明没有有效的扩展名，返回空字符串
        return "";
    }

    /**
     * 上传头像接口（个人中心）
     * @param file
     * @return
     * 功能上的区别
     * originalFilename.lastIndexOf(".")：此方法会返回字符串 originalFilename 里最后一个点号（.）所在的索引位置。要是字符串中不存在点号，就会返回 -1。这主要用于找出文件名里扩展名的起始位置。
     * String ext = "." + originalFilename.split("\\.")[1];：此代码先借助 split("\\.") 方法把字符串 originalFilename 依据点号（.）进行分割，从而形成一个字符串数组。接着取出数组里的第二个元素（索引为 1），并且在其前面添加一个点号，以此得到文件的扩展名。
     */

    @HoneyLogs(operation = "设置头像",type = LogType.UPDATE,menu = MenuType.UnFind)
    @PostMapping("/uploadByUser")
    public ResponseEntity<Map<String, Object>> uploadByUser(@RequestParam("file") MultipartFile file,
                                                      @SessionAttribute("user") User currentUser) {

        Map<String, Object> response = new HashMap<>();
        // 用户校验
        if (currentUser == null) {
            response.put("code", 401);
            response.put("message", "用户未登录");
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
        }
        // 1、file校验
        if (file == null) {
            response.put("code", 400);
            response.put("message", "文件为空");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }
        if (file.isEmpty()) {
            response.put("code", 500);
            response.put("message", "图片上传失败！");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        // 2、file重命名 (a: 1.png  b: 1.png)   方法一
        String originalFilename = file.getOriginalFilename();   // 原来的图片名
        String ext = getFileExtension(originalFilename);        // 文件拓展名
        String uuid = UUID.randomUUID().toString().replace("-", "");   // 生成随机文件名
        String fileName = uuid + ext;   // 新文件名称

        // 3、上传图片
        // 获取应用程序的主目录
        ApplicationHome applicationHome = new ApplicationHome(this.getClass());

       // 构建 src/main/resources/static/images/headshot 路径
        String basePathSrc = Paths.get(applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath(),
                "src", "main", "resources", "static", "images", "headshot").toString();

        // 构建 target/classes/static 路径
        String basePathTarget = Paths.get(System.getProperty("user.dir"), "target/classes/static/images/headshot").toString();

        // 确保 src/main/resources/static/images/headshot 目录存在
        File dirSrc = new File(basePathSrc);
        if (!dirSrc.exists()) {
            if (!dirSrc.mkdirs()) {
                response.put("message", "src/main/resources/static/images/headshot 文件保存目录创建失败");
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
            }
        }

        // 确保 target/classes/static 目录存在
        File dirTarget = new File(basePathTarget);
        if (!dirTarget.exists()) {
            if (!dirTarget.mkdirs()) {
                response.put("message", "target/classes/static/images/headshot 文件保存目录创建失败");
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
            }
        }

        // 构建完整的绝对路径
        File destSrc = new File(basePathSrc, fileName);
        File destTarget = new File(basePathTarget, fileName);

        try {
            // 处理图片大小为 200*200
            Thumbnails.of(file.getInputStream())
                    .size(200, 200)
                    .toFile(destSrc);

            Thumbnails.of(file.getInputStream())
                    .size(200, 200)
                    .toFile(destTarget);


            // 生成相对路径
            String relativePath = "/images/headshot/" + fileName + ".png";

            // 删除旧的头像，防止文件堆积
            String oldPath = currentUser.getImgPath();
            if (oldPath != null && !oldPath.isEmpty()) {
                Path oldFilePathSrc = Paths.get(applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath(),
                        "src/main/resources/static/", oldPath);
                Files.deleteIfExists(oldFilePathSrc); // 安全删除，不存在则忽略

                Path oldFilePathTarget = Paths.get(System.getProperty("user.dir"), "target/classes/static/images/headshot", oldPath);
                Files.deleteIfExists(oldFilePathTarget); // 安全删除，不存在则忽略
            }

            // 更新用户头像路径
            currentUser.setImgPath(relativePath);
            userService.updateById(currentUser); // 确保UserService更新到数据库

            // 手动更新Session中的user对象（如果自动注入未生效）
//            request.getSession().setAttribute("user", currentUser);

            // 处理成功
            response.put("code", 0);
            response.put("message", "文件上传成功");
            response.put("path", relativePath);

            // 清理用户相关的redis缓存
            clearRelatedCaches();

            return ResponseEntity.ok().body(response);
        } catch (IOException e) {
            e.printStackTrace();
            response.put("code", 500);
            response.put("message", "文件上传失败：" + e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    // 用户菜单更换头像接口
    @HoneyLogs(operation = "更换头像",type = LogType.UPDATE,menu = MenuType.User)
    @PostMapping("/uploadByUid")
    public ResponseEntity<Map<String, Object>> uploadByUid(@RequestParam("file") MultipartFile file,
                                                           @RequestParam("userId") Long userId, // 接收用户ID
                                                           @ModelAttribute("headers") HttpHeaders headers) {

        Map<String, Object> response = new HashMap<>();

        // 1. 参数校验
        if (userId == null) {
            response.put("code", 400);
            response.put("message", "用户ID缺失");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        // 2、文件file校验
        if (file == null) {
            response.put("code", 400);
            response.put("message", "文件为空");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }
        if (file.isEmpty()) {
            response.put("code", 500);
            response.put("message", "图片上传失败！");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
        }

        // 3、文件file重命名 (a: 1.png  b: 1.png)   方法一
        String originalFilename = file.getOriginalFilename();   // 原来的图片名
        String ext = getFileExtension(originalFilename);        // 文件拓展名
        String uuid = UUID.randomUUID().toString().replace("-", "");   // 生成随机文件名
        String fileName = uuid + ext;   // 新文件名称

        // 4、上传图片
        // 存储路径配置（推荐使用独立存储目录）
        // 获取应用程序的主目录
        ApplicationHome applicationHome = new ApplicationHome(this.getClass());

        // 构建 src/main/resources/static/images/headshot 路径
        String basePathSrc = Paths.get(applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath(),
                "src", "main", "resources", "static", "images", "headshot").toString();

        // 构建 target/classes/static 路径
        String basePathTarget = Paths.get(System.getProperty("user.dir"), "target/classes/static/images/headshot").toString();

        // 5、确保创建目标目录
        // 确保 src/main/resources/static/images/headshot 目录存在
        File dirSrc = new File(basePathSrc);
        if (!dirSrc.exists()) {
            if (!dirSrc.mkdirs()) {
                response.put("message", "src/main/resources/static/images/headshot 文件保存目录创建失败");
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
            }
        }

        // 确保 target/classes/static 目录存在
        File dirTarget = new File(basePathTarget);
        if (!dirTarget.exists()) {
            if (!dirTarget.mkdirs()) {
                response.put("message", "target/classes/static/images/headshot 文件保存目录创建失败");
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
            }
        }

        // 6. 文件保存路径
        // 构建完整的绝对路径
        File destSrc = new File(basePathSrc, fileName);
        File destTarget = new File(basePathTarget, fileName);

        try {
            // 处理图片大小为 200*200
            Thumbnails.of(file.getInputStream())
                    .size(200, 200)
                    .toFile(destSrc);

            Thumbnails.of(file.getInputStream())
                    .size(200, 200)
                    .toFile(destTarget);


            // 生成相对路径
            String relativePath = "/images/headshot/" + fileName + ".png";

            // 根据用户id来获取具体用户对象
            User user = userService.getById(userId);

//            System.out.println("接收到的用户ID: " + userId);
//            System.out.println("更新的用户头像路径: " + relativePath);

            // 删除旧的头像，防止文件堆积
            assert user != null;
            String oldPath = user.getImgPath();
            if (oldPath != null && !oldPath.isEmpty()) {
                Path oldFilePathSrc = Paths.get(applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath(),
                        "src/main/resources/static/", oldPath);
                Files.deleteIfExists(oldFilePathSrc); // 安全删除，不存在则忽略

                Path oldFilePathTarget = Paths.get(System.getProperty("user.dir"), "target/classes/static/images/headshot", oldPath);
                Files.deleteIfExists(oldFilePathTarget); // 安全删除，不存在则忽略
            }

            // 更新用户头像路径
            user.setImgPath(relativePath);
            userService.updateById(user); // 确保UserService更新到数据库

            // 处理成功
            response.put("code", 0);
            response.put("message", "文件上传成功");
            response.put("path", relativePath);

            // 清理用户相关的redis缓存
            clearRelatedCaches();

            // 设置缓存头
            headers.setCacheControl("max-age=31536000");
            System.out.println("Headers: " + headers);
            return ResponseEntity.ok().body(response);
        } catch (IOException e) {
            e.printStackTrace();
            response.put("code", 500);
            response.put("message", "文件上传失败：" + e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    /**
     * 清理相关缓存
     */
    private void clearRelatedCaches(){
        try {
            redisUtil.deletePattern(CACHE_PREFIX + "*");
            logger.info("成功清理用户相关缓存");
        }catch (Exception e){
            e.printStackTrace();
            logger.error("缓存清理失败", e);
        }
    }
}
